#pragma once
#include <iostream>
#include <unistd.h>
#include <string>
#include <vector>
#include <queue>
#include <string.h>
#include <functional>
#include "log.hpp"
#include "ringqueue.hpp"
#include "lockguard.hpp"
#include "thread.hpp"
template <class T>
class threadpool
{
	void handlertask(const string& name)
	{
		while(1)
		{
			pthread_mutex_lock(&_mutex);
			LOG(DEBUG,"%s进入handler函数\n",name.c_str());
			while(_status&&_q.empty())
				pthread_cond_wait(&_cond,&_mutex);
			if(!_status&&_q.empty())
			{
				pthread_mutex_unlock(&_mutex);//使用锁时，注意锁的释放
				LOG(INFO,"%s exit\n",name.c_str());
				break;
			}

			T tk;
			tk =_q.front();
			_q.pop();
			pthread_mutex_unlock(&_mutex);
			LOG(DEBUG,"%s开始执行任务",name.c_str());
			tk();
		}
	};
	void init()
	{
		fuc_t fuc =bind(&threadpool::handlertask,this,placeholders::_1);//fuc_t是在thread.hpp头文件里的类型
		if(!fuc)
			LOG(DEBUG,"fuc error");
		for(int i =0;i<_thread_num;i++)
		{
			string name ="thread-"+to_string(i);
			_threads.push_back(thread(fuc,name));
		}

	};
	void start()//init和start分开的原因是为了让thread创建出来在运行函数，否则创建的过程中扩容时如果仍存在运行的线程，就会调用之前的函数从而出错

	{
		_status =true;
		for(int i =0;i<_thread_num;i++)
		{
			_threads[i].start();
		}

	}
	threadpool(int num=5)
		:_thread_num(num)
	{
		pthread_mutex_init(&_mutex,nullptr);
		pthread_cond_init(&_cond,nullptr);
	}
	~threadpool()
	{
		pthread_mutex_destroy(&_mutex);
		pthread_cond_destroy(&_cond);
	}
public:
	static threadpool<T>* GetInstance()
	{
		if(_tp==nullptr)//这个判断是如果_tp不为空，就不用竞争锁了
		{
			lockguard lg(&glock);
			if(_tp==nullptr)
			{
				_tp =new threadpool;
				_tp->init();
				_tp->start();
				LOG(DEBUG,"threadpool create success");

			}
			else
			{
				LOG(DEBUG,"threadpool already exist");
			}
		}
		return _tp;
	}
	void push(const T& task)
	{
		pthread_mutex_lock(&_mutex);
		if(_status)
		{
		_q.push(task);
		pthread_cond_signal(&_cond);
		};
		pthread_mutex_unlock(&_mutex);
	};
	void stop()
	{
		pthread_mutex_lock(&_mutex);
		_status = false;
		pthread_cond_broadcast(&_cond);
		pthread_mutex_unlock(&_mutex);
	};
private:
	queue<T> _q;
	vector<thread> _threads;
	static threadpool* _tp; 
	static pthread_mutex_t glock;
	pthread_mutex_t _mutex;
	pthread_cond_t _cond;
	int _thread_num;
	volatile int _status;

};
template<class T>
threadpool<T>* threadpool<T>::_tp =nullptr;
template<class T>
pthread_mutex_t threadpool<T>::glock =PTHREAD_MUTEX_INITIALIZER;


